import React from 'react'
import { Graph, Path } from '@antv/x6'
import '@antv/x6-react-shape'
import { Spin } from 'antd'
import { DagreLayout } from '@antv/layout'
import { getLineage } from './api'
import styles from './index.less'

export class AlgoNode extends React.Component {
  shouldComponentUpdate() {
    const { node } = this.props
    if (node) {
      if (node.hasChanged('data')) {
        return true
      }
    }
    return false
  }

  render() {
    const { node } = this.props
    const data = node?.getData()
    const { label, status = 'default' } = data

    return (
      <div className={`node ${status}`}>
        <div className="iconBackground">
          <i className="iconfont icon-biaoge" />
        </div>
        <span className="label">{label}</span>
      </div>
    )
  }
}

Graph.registerNode(
  'dag-node',
  {
    inherit: 'react-shape',
    width: 220,
    height: 40,
    component: <AlgoNode />,
    ports: {
      groups: {
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 5,
              magnet: true,
              stroke: '#000000',
              strokeWidth: 1,
              fill: '#43A047',
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 5,
              magnet: true,
              stroke: '#000000',
              strokeWidth: 1,
              fill: '#43A047',
            },
          },
        },
        selfLeft: {
          position: 'left',
          attrs: {
            circle: {
              r: 5,
              magnet: true,
              stroke: '#4a4a4a',
              strokeWidth: 1,
              fill: '#0084FF',
            },
          },
        },
        selfRight: {
          position: 'right',
          attrs: {
            circle: {
              r: 5,
              magnet: true,
              stroke: '#4a4a4a',
              strokeWidth: 1,
              fill: '#0084FF',
            },
          },
        },
      },
    },
  },
  true,
)

Graph.registerEdge(
  'dag-edge',
  {
    inherit: 'edge',
    attrs: {
      line: {
        stroke: '#4a4a4a',
        strokeWidth: 1,
        strokeDasharray: 5,
        targetMarker: null,
      },
    },
  },
  true,
)

Graph.registerConnector(
  'algo-connector-model',
  (s, e) => {
    const offset = 5
    let offsetX = 0
    let offsetY = 0
    if (s.y > e.y) {
      offsetY = -offset
      offsetX = offset
    }
    if (s.y < e.y) {
      offsetY = offset
      offsetX = offset
    }

    const x1 = e.x / 3 + (2 / 3) * s.x

    return Path.normalize(
      `M ${s.x} ${s.y}
       L ${x1 - offsetX} ${s.y}
       C ${x1 - offsetX} ${s.y} ${x1} ${s.y} ${x1} ${s.y + offsetY}
       L ${x1} ${e.y - offsetY}
       C ${x1} ${e.y - offsetY} ${x1} ${e.y} ${x1 + offsetX} ${e.y}
       L ${e.x} ${e.y}
      `,
    )
  },
  true,
)

export default class BloodRelationshipMap extends React.PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      loading: false,
    }
    this.mapRef = React.createRef()
    this.dagreLayout = new DagreLayout({
      type: 'dagre',
      rankdir: 'LR',
      ranksep: 80,
      nodesep: 8,
    })
  }

  componentDidMount() {
    this.initMap()
    this.dataChange(this.props.id)
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    if (nextProps.id !== this.props.id) {
      this.dataChange(nextProps.id)
    }
  }

  componentWillUnmount() {
    this.graph && this.graph.dispose()
  }

  // 更新内容
  dataChange = (id) => {
    this.setState({ loading: true })
    getLineage({ tblIdStr: id }).then(
      (res) => {
        setTimeout(() => {
          if (res.tableNodes) {
            this.handleData(res)
          } else {
            this.setState({ loading: false })
          }
        }, 200)
      },
      (error) => {
        console.log(error)
      },
    )
  }

  // 把返回数据处理
  handleData = (res) => {
    const data = {
      nodes: [],
      edges: [],
    }
    const table = []
    res.tableNodes.map((item) => {
      table.push(item.tblIdStr)
      let items = []
      if (item.tblIdStr === this.props.id) {
        items = [
          { group: 'selfLeft', id: `in${item.tblIdStr}` },
          { group: 'selfRight', id: `out${item.tblIdStr}` },
        ]
      } else if (res.lineageDomains) {
        if (res.lineageDomains.find((line) => line.sourceTblIdStr === item.tblIdStr)) {
          items = [
            { group: 'right', id: `out${item.tblIdStr}` },
          ]
        } else {
          items = [
            { group: 'left', id: `in${item.tblIdStr}` },
          ]
        }
      }
      data.nodes.push({
        id: item.tblIdStr,
        shape: 'dag-node',
        data: {
          label: item.tblName,
          status: item.tblIdStr === this.props.id ? 'self' : 'default',
        },
        ports: {
          items,
        },
      })
    })
    if (res.lineageDomains) {
      res.lineageDomains.map((item) => {
        if (table.indexOf(item.sourceTblIdStr) !== -1 && table.indexOf(item.targetTblIdStr) !== -1) {
          data.edges.push({
            source: {
              cell: item.sourceTblIdStr,
              port: `out${item.sourceTblIdStr}`,
            },
            target: {
              cell: item.targetTblIdStr,
              port: `in${item.targetTblIdStr}`,
            },
            shape: 'dag-edge',
          })
        }
      })
    }

    this.setState({
      data,
    }, () => {
      this.init(this.state.data)
      this.setState({
        loading: false,
      })
    })
  }

  // 初始化节点/边
  init = (data) => {
    const model = this.dagreLayout.layout(data)
    this.graph.fromJSON(model)
    this.graph.centerContent()
    this.graph.zoomToFit({
      padding: 20,
      maxScale: 1.5,
      minScale: 0.5,
    })
  }

  initMap = () => {
    this.graph = new Graph({
      container: this.mapRef.current,
      grid: true,
      interacting: false,
      connecting: {
        snap: true,
        allowBlank: false,
        allowLoop: false,
        highlight: true,
        router: { name: 'manhattan' },
        connector: { name: 'algo-connector-model' },
        connectionPoint: 'rect',
        anchor: 'center',
        createEdge() {
          return this.graph.createEdge({
            shape: 'dag-edge',
            attrs: {
              line: {
                strokeDasharray: 5,
              },
            },
            zIndex: -1,
          })
        },
      },
    })
  }

  render() {
    return (
      <Spin spinning={this.state.loading} className={styles.blood_loading}>
        <div className={styles.blood_map} ref={this.mapRef} />
      </Spin>
    )
  }
}
